// $Id: output.cpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#include <ostream>
#include <boost/assert.hpp>
#include <boost/foreach.hpp>
#include <xpgen/output.hpp>
#include <xpgen/model.hpp>

using namespace std;
namespace fs = boost::filesystem;

namespace xpgen {

output::output(output* prev) :
    verbose(false),
    indent_size(4),
    enabled_(true),
    prev_(prev),
    next_(0),
    module_(0)
{
    if (prev_)
        prev_->chain_output(this);
}

output::~output()
{
}

void output::reset()
{
    module_ = 0;
    indent_.clear();
    ns_stack_.clear();

    do_reset();
}

void output::chain_output(output* next)
{
    next_ = next;
}

void output::do_all(module_decl* module)
{
    BOOST_ASSERT(module);

    reset();
    module_ = module;

    if (!enabled_)
        return;

    do_prologue();

    BOOST_FOREACH(interface_decl* itf, module_->interfaces)
    {
        if (filter_interface(itf))
            do_interface(itf);
    }

    do_epilogue();

    // Chain to next
    if (next_)
        next_->do_all(module);
}

bool output::filter_interface(interface_decl* itf)
{
    return itf && !itf->is_root() && itf->is_resolved() &&
            is_interface_included(itf);
}

void output::do_reset()
{
    output* p = prev_;
    if (p) {
        verbose = p->verbose;
        indent_size = p->indent_size;
        input_file = p->input_file;
        output_dir = p->output_dir;
        output_file = p->output_file;
        output_ext = p->output_ext;

        included_interface_qnames = p->included_interface_qnames;
        excluded_interface_qnames = p->excluded_interface_qnames;
    }
}

void output::do_prologue()
{
    // noop
}

void output::do_epilogue()
{
    // noop
}

void output::reset_indent()
{
    indent_.clear();
}

void output::push_indent(unsigned count)
{
    indent_.resize(indent_.size() + indent_size * count, ' ');
}

void output::pop_indent(unsigned count)
{
    size_t size = indent_size * count;
    if (indent_.size() < size)
        indent_.clear();
    else
        indent_.resize(indent_.size() - size, ' ');
}

void output::reset_ns()
{
    ns_stack_.clear();
}

void output::push_ns(const string& ns_name)
{
    ns_stack_.push_back(ns_name);
}

void output::pop_ns()
{
    ns_stack_.pop_back();
}

bool output::is_interface_included(interface_decl* itf) const
{
    if (itf->is_root())
        return true;
    if (excluded_interface_qnames.find(itf->qname)
            != excluded_interface_qnames.end())
        return false;
    return included_interface_qnames.empty() ||
        included_interface_qnames.find(itf->qname)
            != included_interface_qnames.end();
}

} // namespace xpgen
